1   /*
2    * Copyright (C) 2008 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import com.google.common.annotations.GwtCompatible;
20  
21  import java.util.Map;
22  
23  /**
24   * An immutable {@link BiMap} with reliable user-specified iteration order. Does
25   * not permit null keys or values. An {@code ImmutableBiMap} and its inverse
26   * have the same iteration ordering.
27   *
28   * <p>An instance of {@code ImmutableBiMap} contains its own data and will
29   * <i>never</i> change. {@code ImmutableBiMap} is convenient for
30   * {@code public static final} maps ("constant maps") and also lets you easily
31   * make a "defensive copy" of a bimap provided to your class by a caller.
32   *
33   * <p><b>Note:</b> Although this class is not final, it cannot be subclassed as
34   * it has no public or protected constructors. Thus, instances of this class are
35   * guaranteed to be immutable.
36   *
37   * @author Jared Levy
38   * @since 2.0 (imported from Google Collections Library)
39   */
40  @GwtCompatible(serializable = true, emulated = true)
41  public abstract class ImmutableBiMap<K, V> extends ImmutableMap<K, V>
42      implements BiMap<K, V> {
43  
44    /**
45     * Returns the empty bimap.
46     */
47    // Casting to any type is safe because the set will never hold any elements.
48    @SuppressWarnings("unchecked")
49    public static <K, V> ImmutableBiMap<K, V> of() {
50      return (ImmutableBiMap<K, V>) EmptyImmutableBiMap.INSTANCE;
51    }
52  
53    /**
54     * Returns an immutable bimap containing a single entry.
55     */
56    public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1) {
57      return new SingletonImmutableBiMap<K, V>(k1, v1);
58    }
59  
60    /**
61     * Returns an immutable map containing the given entries, in order.
62     *
63     * @throws IllegalArgumentException if duplicate keys or values are added
64     */
65    public static <K, V> ImmutableBiMap<K, V> of(K k1, V v1, K k2, V v2) {
66      return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2));
67    }
68  
69    /**
70     * Returns an immutable map containing the given entries, in order.
71     *
72     * @throws IllegalArgumentException if duplicate keys or values are added
73     */
74    public static <K, V> ImmutableBiMap<K, V> of(
75        K k1, V v1, K k2, V v2, K k3, V v3) {
76      return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3));
77    }
78  
79    /**
80     * Returns an immutable map containing the given entries, in order.
81     *
82     * @throws IllegalArgumentException if duplicate keys or values are added
83     */
84    public static <K, V> ImmutableBiMap<K, V> of(
85        K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
86      return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3),
87          entryOf(k4, v4));
88    }
89  
90    /**
91     * Returns an immutable map containing the given entries, in order.
92     *
93     * @throws IllegalArgumentException if duplicate keys or values are added
94     */
95    public static <K, V> ImmutableBiMap<K, V> of(
96        K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
97      return new RegularImmutableBiMap<K, V>(entryOf(k1, v1), entryOf(k2, v2), entryOf(k3, v3),
98          entryOf(k4, v4), entryOf(k5, v5));
99    }
100 
101   // looking for of() with > 5 entries? Use the builder instead.
102 
103   /**
104    * Returns a new builder. The generated builder is equivalent to the builder
105    * created by the {@link Builder} constructor.
106    */
107   public static <K, V> Builder<K, V> builder() {
108     return new Builder<K, V>();
109   }
110 
111   /**
112    * A builder for creating immutable bimap instances, especially {@code public
113    * static final} bimaps ("constant bimaps"). Example: <pre>   {@code
114    *
115    *   static final ImmutableBiMap<String, Integer> WORD_TO_INT =
116    *       new ImmutableBiMap.Builder<String, Integer>()
117    *           .put("one", 1)
118    *           .put("two", 2)
119    *           .put("three", 3)
120    *           .build();}</pre>
121    *
122    * <p>For <i>small</i> immutable bimaps, the {@code ImmutableBiMap.of()} methods
123    * are even more convenient.
124    *
125    * <p>Builder instances can be reused - it is safe to call {@link #build}
126    * multiple times to build multiple bimaps in series. Each bimap is a superset
127    * of the bimaps created before it.
128    *
129    * @since 2.0 (imported from Google Collections Library)
130    */
131   public static final class Builder<K, V> extends ImmutableMap.Builder<K, V> {
132 
133     /**
134      * Creates a new builder. The returned builder is equivalent to the builder
135      * generated by {@link ImmutableBiMap#builder}.
136      */
137     public Builder() {}
138 
139     /**
140      * Associates {@code key} with {@code value} in the built bimap. Duplicate
141      * keys or values are not allowed, and will cause {@link #build} to fail.
142      */
143     @Override public Builder<K, V> put(K key, V value) {
144       super.put(key, value);
145       return this;
146     }
147 
148     /**
149      * Associates all of the given map's keys and values in the built bimap.
150      * Duplicate keys or values are not allowed, and will cause {@link #build}
151      * to fail.
152      *
153      * @throws NullPointerException if any key or value in {@code map} is null
154      */
155     @Override public Builder<K, V> putAll(Map<? extends K, ? extends V> map) {
156       super.putAll(map);
157       return this;
158     }
159 
160     /**
161      * Returns a newly-created immutable bimap.
162      *
163      * @throws IllegalArgumentException if duplicate keys or values were added
164      */
165     @Override public ImmutableBiMap<K, V> build() {
166       switch (size) {
167         case 0:
168           return of();
169         case 1:
170           return of(entries[0].getKey(), entries[0].getValue());
171         default:
172           return new RegularImmutableBiMap<K, V>(size, entries);
173       }
174     }
175   }
176 
177   /**
178    * Returns an immutable bimap containing the same entries as {@code map}. If
179    * {@code map} somehow contains entries with duplicate keys (for example, if
180    * it is a {@code SortedMap} whose comparator is not <i>consistent with
181    * equals</i>), the results of this method are undefined.
182    *
183    * <p>Despite the method name, this method attempts to avoid actually copying
184    * the data when it is safe to do so. The exact circumstances under which a
185    * copy will or will not be performed are undocumented and subject to change.
186    *
187    * @throws IllegalArgumentException if two keys have the same value
188    * @throws NullPointerException if any key or value in {@code map} is null
189    */
190   public static <K, V> ImmutableBiMap<K, V> copyOf(
191       Map<? extends K, ? extends V> map) {
192     if (map instanceof ImmutableBiMap) {
193       @SuppressWarnings("unchecked") // safe since map is not writable
194       ImmutableBiMap<K, V> bimap = (ImmutableBiMap<K, V>) map;
195       // TODO(user): if we need to make a copy of a BiMap because the
196       // forward map is a view, don't make a copy of the non-view delegate map
197       if (!bimap.isPartialView()) {
198         return bimap;
199       }
200     }
201     Entry<?, ?>[] entries = map.entrySet().toArray(EMPTY_ENTRY_ARRAY);
202     switch (entries.length) {
203       case 0:
204         return of();
205       case 1:
206         @SuppressWarnings("unchecked") // safe covariant cast in this context
207         Entry<K, V> entry = (Entry<K, V>) entries[0];
208         return of(entry.getKey(), entry.getValue());
209       default:
210         return new RegularImmutableBiMap<K, V>(entries);
211     }
212   }
213 
214   private static final Entry<?, ?>[] EMPTY_ENTRY_ARRAY = new Entry<?, ?>[0];
215 
216   ImmutableBiMap() {}
217 
218   /**
219    * {@inheritDoc}
220    *
221    * <p>The inverse of an {@code ImmutableBiMap} is another
222    * {@code ImmutableBiMap}.
223    */
224   @Override
225   public abstract ImmutableBiMap<V, K> inverse();
226 
227   /**
228    * Returns an immutable set of the values in this map. The values are in the
229    * same order as the parameters used to build this map.
230    */
231   @Override public ImmutableSet<V> values() {
232     return inverse().keySet();
233   }
234 
235   /**
236    * Guaranteed to throw an exception and leave the bimap unmodified.
237    *
238    * @throws UnsupportedOperationException always
239    * @deprecated Unsupported operation.
240    */
241   @Deprecated
242   @Override
243   public V forcePut(K key, V value) {
244     throw new UnsupportedOperationException();
245   }
246 
247   /**
248    * Serialized type for all ImmutableBiMap instances. It captures the logical
249    * contents and they are reconstructed using public factory methods. This
250    * ensures that the implementation types remain as implementation details.
251    *
252    * Since the bimap is immutable, ImmutableBiMap doesn't require special logic
253    * for keeping the bimap and its inverse in sync during serialization, the way
254    * AbstractBiMap does.
255    */
256   private static class SerializedForm extends ImmutableMap.SerializedForm {
257     SerializedForm(ImmutableBiMap<?, ?> bimap) {
258       super(bimap);
259     }
260     @Override Object readResolve() {
261       Builder<Object, Object> builder = new Builder<Object, Object>();
262       return createMap(builder);
263     }
264     private static final long serialVersionUID = 0;
265   }
266 
267   @Override Object writeReplace() {
268     return new SerializedForm(this);
269   }
270 }